﻿// ==========================================================
// File: Universal.WebAPI.Core.BaseClient.cs
// Created: 14.12.2014
// Created By: Tim cadenbach
// 
// Copyright (C) 2014 Tim Cadenbach
// License: Apache License 2.0
// ==========================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Universal.WebAPI.Generic;
using Universal.WebAPI.Interfaces;
using Universal.WebAPI.Response;

namespace Universal.WebAPI
{
  public class BaseClient : IBaseClient
  {
    protected readonly string serviceURL;
    public string Token { get; set; }
   public BaseClient(string endpoint)
    {
      serviceURL = endpoint;
    }

    public TimeSpan Timeout { get; set; }
    public Uri BaseAddress { get; private set; }

    public void AddHeader(string key, string value)
    {
      throw new NotImplementedException();
    }

    public void RemoveHeader(string key)
    {
      throw new NotImplementedException();
    }


    /// <summary>
    /// Post the given object as Json String
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="endpoint"></param>
    /// <param name="dto"></param>
    /// <param name="format"></param>
    /// <returns></returns>
    public async Task<ServiceResponse<T>> PostAsync<T>(string endpoint, object dto, RequestFormat format)
    {

      HttpContent requestContent = new StringContent(JsonConvert.SerializeObject(dto), Encoding.UTF8, "application/json");
      using (var client = new HttpClient())
      {
        client.BaseAddress = new Uri(serviceURL);
     
        HttpResponseMessage responseMessage = await client.PostAsync(endpoint, requestContent);

        var response = new ServiceResponse<T>(responseMessage.StatusCode);

        using (Stream responseStream = await responseMessage.Content.ReadAsStreamAsync())
        {

          response.Content = new StreamReader(responseStream).ReadToEnd();

          return (ServiceResponse<T>)JsonConvert.DeserializeObject(response.Content, typeof(T));
        }
      }
    }

    /// <summary>
    /// Post collection of string values
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="endpoint"></param>
    /// <param name="content"></param>
    /// <param name="format"></param>
    /// <returns></returns>
    public Task<ServiceResponse<T>> PostStringAsync<T>(string endpoint, string content, RequestFormat format)
    {
      throw new NotImplementedException();
    }

    /// <summary>
    /// Post a collection of Strings e.g ?string1=test&string2=33 etc.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="endpoint"></param>
    /// <param name="contentDict"></param>
    /// <param name="format"></param>
    /// <returns></returns>
    public async Task<T> PostValuesAsync<T>(string endpoint, Dictionary<string, string> contentDict,
      RequestFormat format)
    {
      var sb = new StringBuilder();
      bool IsFirstEntry = true;
      foreach (var entry in contentDict)
      {
        if (!IsFirstEntry) sb.Append("&");
        sb.Append(entry.Key + "=" + entry.Value);

        if (IsFirstEntry) IsFirstEntry = false;
      }

      HttpContent requestContent = new StringContent(sb.ToString(), Encoding.UTF8, "application/x-www-form-urlencoded");
      using (var client = new HttpClient())
      {
        client.BaseAddress = new Uri(serviceURL);


        HttpResponseMessage responseMessage = await client.PostAsync(endpoint, requestContent);

        var response = new ServiceResponse<T>(responseMessage.StatusCode);

        using (Stream responseStream = await responseMessage.Content.ReadAsStreamAsync())
        {

          response.Content = new StreamReader(responseStream).ReadToEnd();

          return (T) JsonConvert.DeserializeObject(response.Content, typeof (T));
        }
      }
    }

    /// <summary>
    /// Get without Authentication
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="endpoint"></param>
    /// <param name="format"></param>
    /// <returns></returns>
    public async Task<ServiceResponse<T>> GetAsync<T>(string endpoint, RequestFormat format)
    {
      using (var client = new HttpClient())
      {
        client.BaseAddress = new Uri(serviceURL);
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        var data = await client.GetAsync(endpoint);

        if (!data.IsSuccessStatusCode) return new ServiceResponse<T>(HttpStatusCode.InternalServerError);

        using (Stream responseStream = await data.Content.ReadAsStreamAsync())
        {
          string jsonMessage = new StreamReader(responseStream).ReadToEnd();
          return new ServiceResponse<T>(HttpStatusCode.OK) { ContentObj = JsonConvert.DeserializeObject(jsonMessage, typeof(T)) };
        }

      }
    }

    /// <summary>
    /// Authenticated Get
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="endpoint"></param>
    /// <param name="header"></param>
    /// <returns></returns>
    public async Task<ServiceResponse<T>> GetAsync<T>(string endpoint, AuthenticationHeaderValue header)
    {

      using (var client = new HttpClient())
      {
        client.BaseAddress = new Uri(serviceURL);
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Token);
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        var data = await client.GetAsync(endpoint);

        if (!data.IsSuccessStatusCode) return new ServiceResponse<T>(HttpStatusCode.InternalServerError);

          using (Stream responseStream = await data.Content.ReadAsStreamAsync())
          {
            string jsonMessage = new StreamReader(responseStream).ReadToEnd();
            return new ServiceResponse<T>(HttpStatusCode.OK){ContentObj = JsonConvert.DeserializeObject(jsonMessage, typeof(T))};
          }

        }
    }

    /// <summary>
    /// Get Authenticated Data using Parameters
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="endpoint"></param>
    /// <param name="values"></param>
    /// <param name="format"></param>
    /// <returns></returns>
    public async Task<ServiceResponse<T>> GetAsync<T>(string endpoint, Dictionary<string, string> values, RequestFormat format)
    {

      var sb = new StringBuilder();
      bool IsFirstEntry = true;
      foreach (var entry in values)
      {
        if (!IsFirstEntry) sb.Append("&");
        sb.Append(entry.Key + "=" + entry.Value);

        if (IsFirstEntry) IsFirstEntry = false;
      }

      using (var client = new HttpClient())
      {
        client.BaseAddress = new Uri(serviceURL);
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Token);
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        var data = await client.GetAsync(endpoint + sb);

        if (!data.IsSuccessStatusCode) return new ServiceResponse<T>(HttpStatusCode.InternalServerError);

        using (Stream responseStream = await data.Content.ReadAsStreamAsync())
        {
          string jsonMessage = new StreamReader(responseStream).ReadToEnd();
          return new ServiceResponse<T>(HttpStatusCode.OK) { ContentObj = JsonConvert.DeserializeObject(jsonMessage, typeof(T)) };
        }

      }
    }
  }
}